package me.edzh.spring.bootstrap.service.impl;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.OSSObjectSummary;
import com.aliyun.oss.model.ObjectListing;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.exceptions.ServerException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import lombok.extern.log4j.Log4j;
import me.edzh.spring.bootstrap.service.ObjectiveStorageService;
import me.edzh.spring.bootstrap.utils.ResultCode;
import me.edzh.spring.bootstrap.utils.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.io.*;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Log4j
@Service("ossServiceImpl")
public class OSSServiceImpl implements ObjectiveStorageService {

    @Autowired(required = false)
    private OSSConfig ossConfig;

    private OSS oss;

    private DefaultAcsClient client;

    @PostConstruct
    private void init() {
        if (ossConfig != null) {
            oss = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAK(), ossConfig.getAS());

            IClientProfile profile = DefaultProfile.getProfile(ossConfig.getRegion(), ossConfig.getAK(), ossConfig.getAS());
            client = new DefaultAcsClient(profile);


        }
    }

    @PreDestroy
    private void onDestroy() {
        if (oss != null) {
            oss.shutdown();
        }
    }

    @Override
    public String signUrl(String url) {
        Date expiration = new Date(new Date().getTime() + ossConfig.getURLSignExpiration());
        try {
            URL from = new URL(url);
            String path = from.getPath();
            URL u = oss.generatePresignedUrl(ossConfig.getBucketName(), path.substring(1), expiration);

            String result = "https://private.static.ylmvip.cn" + u.getPath() + "?" + u.getQuery();
            log.info("signed url: " + result);

            return result;
        } catch (Exception e) {
            log.warn("转换url失败:" + url, e);
            return null;
        }
    }

    @Override
    public Object getToken() {
        AssumeRoleRequest request = new AssumeRoleRequest();
        request.setVersion("2015-04-01");
        request.setMethod(MethodType.POST);
        request.setProtocol(ProtocolType.HTTPS);
        request.setRoleArn(ossConfig.getRoleArn());
        request.setRoleSessionName("me.edzh");
        request.setDurationSeconds(ossConfig.getDuration());
        try {
            AssumeRoleResponse resp = client.getAcsResponse(request);
            return resp.getCredentials();

        } catch (ClientException s) {
            log.error(s);
            throw new ServiceException(ResultCode.ERROR_OS_GET_TOKEN_ERR, s.getErrCode() + s.getErrMsg());
        }
    }

    @Override
    public void putObject(String key, byte[] content) {
        // 创建PutObjectRequest对象。
        // <yourObjectName>表示上传文件到OSS时需要指定包含文件后缀在内的完整路径，例如abc/efg/123.jpg。
        PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), key, new ByteArrayInputStream(content));

        // 如果需要上传时设置存储类型与访问权限，请参考以下示例代码。
        // ObjectMetadata metadata = new ObjectMetadata();
        // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
        // metadata.setObjectAcl(CannedAccessControlList.Private);
        // putObjectRequest.setMetadata(metadata);

        // 上传字符串。
        oss.putObject(putObjectRequest);
    }

    @Override
    public List<String> ls(String prefix) {
        ObjectListing objectListing = oss.listObjects(ossConfig.getBucketName(), prefix);
        List<OSSObjectSummary> sums = objectListing.getObjectSummaries();

        if (sums == null) {
            return new ArrayList<>();
        }
        return sums.parallelStream()
                .map(OSSObjectSummary::getKey)
                .collect(Collectors.toList());
    }

    public interface OSSConfig {
        String getAK();

        String getAS();

        String getEndPoint();

        /**
         * 在COS是可用区, 在OSS是endpoint
         */
        String getRegion();

        String getBucketName();

        String getRoleArn();

        Long getDuration();

        Long getURLSignExpiration();
    }
}
